<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>proxy</title>
</head>

<body>
</body>
<script>
  {
    var person = {
      name: " 张三 "
    };
    // get方法用于拦截某个属性的读取操作
    var proxy = new Proxy(person, {
      get: (target, property) => {
        if (property in target) {
          return target[property];
        } else {
          throw new ReferenceError("Property \"" + property + "\" does not exist.");
        }
      }
    })
    console.log(proxy.name) // " 张三 "
    // con(proxy.age) //  抛出一个错误
  } {
    //如果访问目标对象不存在的属性， 会抛出一个错误。 
    // 如果没有这个拦截函数， 访问不存在的属性， 只会返回undefined。
    let proto = new Proxy({}, {
      get(target, propertyKey, receiver) {
        console.log('GET ' + propertyKey);
        return target[propertyKey];
      }
    });
    let obj = Object.create(proto);
    obj.xxx // "GET xxx"
  } {
    //使用get拦截， 实现数组读取负数的索引
    function createArray(...elements) {
      let handler = {
        get(target, propKey, receiver) {
          let index = Number(propKey);
          if (index < 0) {
            propKey = String(target.length + index);
          }
          // Reflect 是一个内置的对象，它提供拦截 JavaScript 操作的方法。
          // 这些方法与proxy handlers的方法相同。Reflect不是一个函数对象，因此它是不可构造的。
          // Reflect.get(target, propertyKey[, receiver])
          // 获取对象身上某个属性的值， 类似于 target[name]。
          return Reflect.get(target, propKey, receiver);
        }
      };
      let target = [];
      target.push(...elements);
      return new Proxy(target, handler);
    }
    let arr = createArray('a', 'b', 'c');
    console.log(arr[-1]) // c
  } {
    //利用 Proxy， 可以将读取属性的操作（ get）， 
    // 转变为执行某个函数， 从而实现属性的链式操作。
    var pipe = (function () {
      return function (value) {
        var funcStack = [];
        var oproxy = new Proxy({}, {
          get: function (pipeObject, fnName) {
            if (fnName === 'get') {
              //reduce 
              // 第一个参数 val 为累加之后的结果
              //第二个参数 fn 为每次
              return funcStack.reduce(function (val, fn) {
                return fn(val);
              }, value);
            }
            funcStack.push(window[fnName]);
            return oproxy;
          }
        });
        return oproxy;
      }
    }());
    var double = n => n * 2;
    var pow = n => n * n;
    var reverseInt = n => n.toString().split("").reverse().join("") | 0;
    console.log(pipe(3).double.pow.reverseInt.get) // 63
  }
</script>

</html>